package xyz.cerberu.cet.global.filter;

import com.fasterxml.jackson.annotation.JsonFilter;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.BeanPropertyFilter;
import com.fasterxml.jackson.databind.ser.FilterProvider;
import com.fasterxml.jackson.databind.ser.PropertyFilter;
import com.fasterxml.jackson.databind.ser.PropertyWriter;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * @author β世界
 * Created on 8:47
 * @Description 自定义jackson字段过滤器
 */
@JsonFilter("JacksonFilter")
@Component
public class JacksonJsonFilter extends FilterProvider {
    Map<Class<?>, Set<String>> includeMap = new HashMap<>();
    Map<Class<?>, Set<String>> filterMap = new HashMap<>();

    /**
     * @author β世界 on 23:14 2021/3/2
     * 用于向包含字段中添加
     * @param type: 类
     * @param fields: 字段数组
     **/
    public void include(Class<?> type, String[] fields) {
        addToMap(includeMap, type, fields);
    }

    /**
     * @author β世界 on 23:14 2021/3/2
     * 用于向过滤字段中添加
     * @param type: 类
     * @param fields: 字段数组
     **/
    public void filter(Class<?> type, String[] fields) {
        addToMap(filterMap, type, fields);
    }

    /**
     * @author β世界 on 23:18 2021/3/2
     * 添加的相应的字段属性
     * @param map: 存储字段的map
     * @param type: 类型
     * @param fields: 字段数组
     **/
    private void addToMap(Map<Class<?>, Set<String>> map, Class<?> type, String[] fields) {
        Set<String> fieldSet = map.getOrDefault(type, new HashSet<>());
        fieldSet.addAll(Arrays.asList(fields));
        map.put(type, fieldSet);
    }

    @Override
    public BeanPropertyFilter findFilter(Object filterId) {
        throw new UnsupportedOperationException("Access to deprecated filters not supported");
    }

    /**
     * @author β世界 on 23:18 2021/3/2
     * 主要的过滤法方法
     * @param filterId:
     * @param valueToFilter:
     * @return com.fasterxml.jackson.databind.ser.PropertyFilter
     **/
    @Override
    public PropertyFilter findPropertyFilter(Object filterId, Object valueToFilter) {
        return new SimpleBeanPropertyFilter(){
            @Override
            public void serializeAsField(Object pojo, JsonGenerator jgen, SerializerProvider prov, PropertyWriter writer)
                    throws Exception {
                // 判断一个这个类中的一个字段是否需要被过滤
                if (apply(pojo.getClass(), writer.getName())) {
                    writer.serializeAsField(pojo, jgen, prov);
                } else if (!jgen.canOmitFields()) {
                    writer.serializeAsOmittedField(pojo, jgen, prov);
                }
            }
        };
    }

    /**
     * @author β世界 on 23:13 2021/3/2
     * 主要用于判断是否处理属性的方法
     * @param type: 被处理的类
     * @param name: 属性名
     * @return boolean
     **/
    public boolean apply(Class<?> type, String name) {
        Set<String> includeFields = includeMap.get(type);
        Set<String> filterFields = filterMap.get(type);
        // 如果这个属性包含在include字段里面，就留下
        if (includeFields != null && includeFields.contains(name)) {
            return true;
        // 如果这个属性不在filter字段里面，就留下
        } else if (filterFields != null && !filterFields.contains(name)) {
            return true;
        // 如果include和filter的字段都是空的，那么这个字段也留下
        } else if (includeFields == null && filterFields == null) {
            return true;
        }
        // 如果上述的条件都不是，那么就过滤掉这个属性
        return false;
    }
}
